var $ = exports
var au = require("arrayUtils")
var objectUtils = require("objectUtils")

var log = java.util.logging.Logger.getLogger("sandro/clientMod")

var authorizedModNames = /^[\/a-zA-Z0-9]+$/

var simpleDeps = function(jsonDep, acum) {
	if (typeof jsonDep === "string") {
		acum[jsonDep] = acum[jsonDep] || [] 
		return [jsonDep]
	} else if ( au.isArray(jsonDep) ) {
		return jsonDep.map(function(e) {
			return simpleDeps(e,acum)
		}).flatten()
	} else if (jsonDep.constructor === Object) { //Object
		var rv = []
		for (var i in jsonDep) {
			acum[i] = acum[i] || []
			rv.push(i)
			acum[i] = acum[i].concat(simpleDeps(jsonDep[i], acum))
		}
		return rv
	} else {
		return [] // functions, regexps, and other things do not define dependencies
	}
}

var dependsProto = {
	init: function(jsonDep) {
		this.deps = {} 
		simpleDeps(jsonDep, this.deps)
	},
	resolve: function(mods) {
		var acum = {}
		var that = this
		mods.forEach(function(mod){
			that.resolve0(mod, acum)
		})
		var rv = []
		for ( var i in acum ) {
			rv.push(i)
		}
		return rv
	},
	resolve0: function(mod, acum) {
		
		if( acum[mod] ) {
			return
		}
		if( !this.handled(mod)) {
			return
		}
		
		var that = this
		acum[mod] = true
		this.deps[mod].forEach(function(child) {
			that.resolve0(child, acum)
		})
	},
	handled: function(mod) {
		return mod in this.deps
	}
}

var depends = function(jsonDep) {
	var dep = objectUtils.beget(dependsProto)
	dep.init(jsonDep)
	return dep
}

var modCode = function(mods) {
	//"require", "exports", "module"
	var rv = "{"
	for (var i in mods) {
		rv += "\"" + i + "\": function(require, exports, module) {\n" + 
			mods[i] + ";return exports},\n"
	}
	rv += "}"
	return rv
}
/**
 * Returns the action that retrieves the modules and glues them to be sent to the browser.
 * 
 * @param jsonDeps has the list of dependencies that authorized modules have. 
 * All modules listed in jsonDeps may be retrieved from the client.
 */
$.action = function(jsonDeps) {
	var deps = depends(jsonDeps) 
	return function(request, response) {
		var modNames = deps.resolve( request.getParameter("modules").split(",") )
		var mods = modNames.reduce(function(acum,name) {
			if (authorizedModNames.test(name)) {
				acum["/" + name] = "" + require.loadMod(name)
			}
			return acum
		}, {})
		
		var template = "" + require.loadMod("sandro/clientModTemplate")
		response.status = 200
		response.contentType = "text/javascript"
		response.writer.print(
			template.replace("/*MOD_CODE*/", function() { return modCode(mods) })
		)
	}
}

